from decimal import Decimal
from rest_framework import serializers
from rest_framework.response import Response

from goods.models import SKU
from orders.models import OrderInfo, OrderGoods


class OrdersPlacesSerializer(serializers.ModelSerializer):
    count = serializers.IntegerField(label='个数')

    class Meta:
        model = SKU
        fields = ['id','name','price','default_image_url','count']


class PlacesOrdersSerializer(serializers.Serializer):
    skus = OrdersPlacesSerializer(many=True)

    freight =serializers.DecimalField(max_digits=10, decimal_places=2)


class OrderSerializer(serializers.ModelSerializer):

    class Meta:
        model = OrderInfo
        fields = ('order_id', 'address', 'pay_method')
        read_only_fields = ('order_id',)
        extra_kwargs = {
            'address': {
                'write_only': True,
                'required': True,
            },
            'pay_method': {
                'write_only': True,
                'required': True
            }
        }


    '''
    分为两个数据表
    1 先保存第一个表　在进行第二个表的保存
    2

    '''
    '''
    如何实现数据库的事物，数据库的事物是如何产生　都有哪些解决办法　悲观锁　和　乐观锁　
    主要是在同一个时间　多个用户同时进行订单的结算　也就是在多个商品中　因为数据库支持多个用户操作，
    同时对数据库数据进行获取和修改　所以订单上两个人同时都已经完成对订单的支付　但是数据库中销量只是增加一次，
    悲观锁　当两个用户同时进行查询时，　两件商品　同时对先抢到的数据进行枷锁，等待另一个商品的释放，容易形成死锁
    乐观锁　是在查询的时间进行一次记录，在更新之前在进行数据库的校验，判断是否数据一致，不一致则等待

    '''

    def create(self, validated_data):
        from django.db import transaction

        address = validated_data.get('address')
        pay_method = validated_data.get('pay_method')

        user = self.context.get('request').user
        from django.utils import timezone
        from .models import OrderInfo
        order_id = timezone.now().strftime('%Y%M%D%H%M%S')+('%09d'%user.id)
        # 判断支付
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            status = OrderInfo.ORDER_STATUS_CHOICES['UNPAID']
        else:
            status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        # 在事物中开启这个
        with transaction.atomic():
            # 如果出现问题就回滚这个位置
            save_point = transaction.savepoint()

            order = OrderInfo.object.create(
                order_id = order_id,
                user = user,
                address = address,
                pay_method=pay_method,
                total_count = 0,
                total_amount=Decimal('0'),
                freight=Decimal('10.0'),
                status=status
            )
            from django_redis import get_redis_connection
            # 连接redis 数据库
            redis_conn = get_redis_connection('cart')
            # 获取reids数据库中的数据哈希表中　集合中
            sku_id_count = redis_conn.hgetall('cart_%s'%user.id)
            selected_redis = redis_conn.smembers('cart_slected_%s'%user.id)

            # 对redis 取出的数据进行转换　只转换已经存在的数据
            redis_selected_cart = {}
            for sku_id in selected_redis:
                redis_selected_cart[int(sku_id)] = int(sku_id_count[sku_id])

            # 对选中的商品进行
            for sku_id,count in redis_selected_cart.items():
                while True:
                    try:
                        sku = SKU.objects.get(pk = sku_id)
                    except SKU.DoesNotExist:
                        # 这个位置是因为涉及到数据库的问题，需要之前对数据库进行的操作进行回滚
                        transaction.savepoint_rollback(save_point)
                        return Response('商品不存在')

                    # 进行商品数量的判断
                    if sku.stock < count:
                        # 在这个位置因为数据的问题，之前的保存的状态都要进行回滚
                        transaction.savepoint_rollback(save_point)
                        return Response('库存不足')
                    # 更新操作之前先进性数据库的查询
                    old_stock = sku.stock
                    # 进行库存和销量的判断
                    new_stock = sku.stock - count
                    new_stale = sku.state + count

                    retc = SKU.objects.filter(pk = sku.id,stock = old_stock).update(stock = new_stock,sales = new_stale)

                    if retc== 0:
                        continue
                    # 进行销售和数量的前后累加和累减
                    order.total_count -= count
                    order.total_amount += (count*user.price)
                    # 商品入库
                    OrderGoods.objects.create(
                        order = order,
                        sku = sku,
                        count = count,
                        price = sku.price

                    )
                    break
                order.save()
                # 在这一步没有问题就可以提交
                transaction.savepoint_commit(save_point)

        return order

